<template>
  <div class="main" id="root">
    <div id="headPanel" style="text-align: center">
      <div class="btn-group">
        <div class="btn" title="圆形节点" @mousedown="startDrag('Circle',$event)">
          <i class="iconfont icon-circle"></i>
        </div>
        <div class="btn" title="正方形节点" @mousedown="startDrag('Rect',$event)">
          <i class="iconfont icon-square"></i>
        </div>
        <div class="btn" title="条件节点">
          <i class="iconfont icon-square rotate-square" @mousedown="startDrag('polygon',$event)"></i>
        </div>
        <div class="btn-group_tips" v-if="showTips">
          拖拽生成</br>资产拓扑图形
        </div>
      </div>
      <div class="btn-group">
        <Tooltip content="直线箭头" placement="bottom">
          <div :class=" ['btn',currentArrow === 1?'currentArrow':'']" @click="changeEdgeType('normal')">
            <i class="iconfont icon-ai28"></i>
          </div>
        </Tooltip>
        <Tooltip content="曲线箭头" placement="bottom">
          <div :class=" ['btn',currentArrow === 2?'currentArrow':'']" @click="changeEdgeType('smooth')">
            <i class="iconfont icon-Down-Right"></i>
          </div>
        </Tooltip>
        <Tooltip content="直角箭头" placement="bottom">
          <div :class=" ['btn',currentArrow === 3?'currentArrow':'']" @click="changeEdgeType()">
            <i class="iconfont icon-jiantou"></i>
          </div>
        </Tooltip>
      </div>
      <div class="btn-group">
        <div class="btn" @click="changeMode('edit')" title="选择模式">
          <i class="iconfont icon-mousepointershubiao"></i>
        </div>
        <div class="btn" @click="changeMode('drag')" title="拖拽模式">
          <i class="iconfont icon-tuozhuai"></i>
        </div>
      </div>
      <div class="btn-group">
        <Tooltip content="删除" placement="bottom">
          <div class="btn" @click="deleteNode()" style="margin-top: 5px;">
            <i class="iconfont icon-shanchu"></i>
          </div>
        </Tooltip>
        <Tooltip content="保存PNG" placement="bottom">
          <div class="btn" @click="saveToPNG()" title="保存">
            <i class="iconfont icon-baocun"></i>
          </div>
        </Tooltip>
      </div>
      <div class="btn-group">
        <Tooltip content="复制" placement="bottom">
          <div class="btn" @click="copyNode()" style="margin-top: 5px;">
            <i class="ivu-icon ivu-icon-ios-copy"></i>
          </div>
        </Tooltip>
        <Tooltip content="粘贴" placement="bottom">
          <div class="btn" @click="parseNode()" title="保存">
            <i class="ivu-icon ivu-icon-ios-copy"></i>
          </div>
        </Tooltip>
      </div>
    </div>
    <div id="stencil" class="leftPanel"></div>
    <div class="container" id="containerChart"></div>
    <RightDrawer class="right_drawer" :drawerType="type" :selectCell="selectCell" :graph="graph" :grid="grid"
                 @deleteNode="deleteNode"></RightDrawer>
    <Dropdown transfer placement="right-start" trigger="custom" ref="contextMenu"
              :visible="visible"
              @on-clickoutside="handleCancel" @on-click="rightMenuClick">
      <Dropdown-menu slot="list">
        <Dropdown-item name="1">删除节点</Dropdown-item>
        <Dropdown-item name="2">复制节点</Dropdown-item>
        <Dropdown-item name="3">粘贴节点</Dropdown-item>
        <Dropdown-item name="4">取 消</Dropdown-item>
      </Dropdown-menu>
    </Dropdown>
  </div>

</template>
<script>
import '@antv/x6-vue-shape'
import {Graph, Shape, Addon, FunctionExt, DataUri} from '@antv/x6';
import RightDrawer from './components/RightDrawer';
import insertCss from 'insert-css';
import {startDragToGraph} from './Graph/methods.js'

const data = {};
export default {
  data() {
    return {
      ports: {
        groups: {
          // 输入链接桩群组定义
          top: {
            position: 'top',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#2D8CF0',
                strokeWidth: 2,
                fill: '#fff',
              },
            },
          },
          // 输出链接桩群组定义
          bottom: {
            position: 'bottom',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#2D8CF0',
                strokeWidth: 2,
                fill: '#fff',
              },
            },
          },
          left: {
            position: 'left',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#2D8CF0',
                strokeWidth: 2,
                fill: '#fff',
              },
            },
          },
          right: {
            position: 'right',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#2D8CF0',
                strokeWidth: 2,
                fill: '#fff',
              },
            },
          },
        },
        items: [
          {
            id: 'port1',
            group: 'top',
          },
          {
            id: 'port2',
            group: 'bottom',
          },
          {
            id: 'port3',
            group: 'left',
          },
          {
            id: 'port4',
            group: 'right',
          }
        ],
      },
      graph: '',
      value1: true,
      type: 'grid',
      selectCell: '',
      connectEdgeType: {  //连线方式
        connector: 'normal',
        router: {
          name: ''
        }
      },
      showTips: false,
      currentArrow: 1,
      grid: { // 网格设置
        size: 20,      // 网格大小 10px
        visible: true, // 渲染网格背景
        type: 'mesh',
        args: {
          color: '#D0D0D0',
          thickness: 1,     // 网格线宽度/网格点大小
          factor: 10,
        },
      },
      visible: false,
      locator: null,
      posX: 0,
      posY: 0,
      rightId: "",
      rightNode: [],
      dx: 20,
      dy: 20
    }
  },
  components: {
    RightDrawer
  },
  methods: {
    copyNode() {
      const cells = this.graph.getSelectedCells().length == 0 ? this.rightNode : this.graph.getSelectedCells();
      if (cells && cells.length) {
        this.graph.copy(cells)
        this.$Message.success('复制成功')
      } else {
        this.$Message.info('请先选中节点再复制')
      }
    },
    parseNode() {
      if (this.graph.isClipboardEmpty()) {
        this.$Message.info('剪切板为空，不可粘贴')
      } else {
        const cells = this.graph.paste({
          offset: {dx: this.dx, dy: this.dy}
        });
        this.graph.cleanSelection()
        this.graph.select(cells)
        this.$Message.success('粘贴成功')
      }
    },
    rightMenuClick(item) {
      const id = parseInt(item);
      switch (id) {
        case 1:
          this.delete(this.rightId);
          break;
        case 2:
          this.copyNode();
          break;
        case 3:
          this.parseNode();
          break;
        default:
          this.visible = false;
          break;
      }
    },
    handleCancel() {
      this.visible = false
      this.removeLocator();
    },
    removeLocator() {
      if (this.locator) document.body.removeChild(this.locator)
      this.locator = null
    },
    createLocator() {
      // 获取Dropdown
      const contextmenu = this.$refs.contextMenu
      // 创建locator
      const locator = document.createElement('div')
      locator.style.cssText = `position:fixed;left:${this.posX}px;top:${this.posY}px`
      document.body.appendChild(locator)
      // 将locator绑定到Dropdown的reference上
      contextmenu.$refs.reference = locator
      this.locator = locator
    },
    initX6() {
      const _that = this
      this.graph = new Graph({
        container: document.getElementById('containerChart'),
        width: window.innerWidth,
        height: '100%',
        grid: _that.grid,
        resizing: { //调整节点宽高
          enabled: true,
          orthogonal: false,
        },

        snapline: true,
        interacting: {
          edgeLabelMovable: true
        },
        clipboard: {
          enabled: true
        },
        following: true,
        strict: true,
        selecting: {
          enabled: true,
          rubberband: true
        },
        multiple: true,
        connecting: { // 节点连接
          anchor: 'center',
          connectionPoint: 'anchor',
          allowBlank: false,
          snap: true,
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#1890ff',
                  strokeWidth: 1,
                  targetMarker: {
                    name: 'classic',
                    size: 8
                  },
                  strokeDasharray: 0, //虚线
                  style: {
                    animation: 'ant-line 30s infinite linear',
                  },
                },
              },
              label: {
                text: ''
              },
              connector: _that.connectEdgeType.connector,
              router: {
                name: _that.connectEdgeType.router.name || ''
              },
              zIndex: 0
            })
          },
        },
        highlighting: {
          magnetAvailable: {
            name: 'stroke',
            args: {
              padding: 4,
              attrs: {
                strokeWidth: 4,
                stroke: '#6a6c8a'
              }
            }
          }
        },
      });
      insertCss(`
              @keyframes ant-line {
                to {
                    stroke-dashoffset: -1000
                }
              }
            `)
      this.graph.fromJSON(data)
      this.graph.history.redo();
      this.graph.history.undo();

      //this.graph.scrollToContent();
      // 鼠标移入移出节点
      this.graph.on('node:mouseenter', FunctionExt.debounce(() => {
          const container = document.getElementById('containerChart')
          const ports = container.querySelectorAll(
            '.x6-port-body'
          )
          this.showPorts(ports, true)
        }),
        500
      );

      this.graph.on("cell:contextmenu", ({e, node}) => {
        this.rightId = node.id;
        this.rightNode = [];
        console.log(node)
        this.rightNode.push(node);
        const clientX = e.clientX;
        const clientY = e.clientY;

       // this.dx = clientX - this.posX;
       // this.dy = clientY - this.posY;

        if (this.posX !== clientX) this.posX = clientX + 10;
        if (this.posY !== clientY) this.posY = clientY + 10;
        if (this.trigger !== 'custom') {
          this.createLocator()
          this.visible = true
        }
      });

      this.graph.on('blank:contextmenu', ({e}) => {
        const clientX = e.clientX;
        const clientY = e.clientY;
        const cells = this.graph.getCellsInClipboard();

        if (!cells || cells.length == 0) return;
        if (this.posX !== clientX) this.posX = clientX + 10;
        if (this.posY !== clientY) this.posY = clientY + 10;
        if (this.trigger !== 'custom') {
          this.createLocator()
          this.visible = true
        }
      })
      this.graph.on('node:mouseleave', () => {
        const container = document.getElementById('containerChart')
        const ports = container.querySelectorAll(
          '.x6-port-body'
        )
        this.showPorts(ports, false)
      })
      this.graph.on('blank:click', () => {
        this.type = 'grid'
      })
      this.graph.on('cell:click', ({cell}) => {
        this.type = cell.isNode() ? 'node' : 'edge'
      })
      this.graph.on('selection:changed', (args) => {
        args.added.forEach(cell => {
          this.selectCell = cell;
          if (cell.isEdge()) {
            cell.isEdge() && cell.attr('line/strokeDasharray', 5) //虚线蚂蚁线
            cell.addTools([
              {
                name: 'vertices',
                args: {
                  padding: 4,
                  attrs: {
                    strokeWidth: 0.1,
                    stroke: '#2d8cf0',
                    fill: '#ffffff',
                  }
                },
              },
            ])
          }
        })
        args.removed.forEach(cell => {
          cell.isEdge() && cell.attr('line/strokeDasharray', 0)  //正常线
          cell.removeTools()
        })
      })
      this.initLeftPanel();
    },
    initLeftPanel() {
      const graph = this.graph;
      console.log(startDragToGraph.ports);
      Graph.registerNode(
        'custom-rect',
        {
          inherit: 'rect',
          width: 66,
          height: 36,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#5F95FF',
              fill: '#EFF4FF',
            },
            text: {
              fontSize: 12,
              color: '#262626',
            },
          },
          ports: this.ports
        },
        true,
      )

      Graph.registerNode(
        'custom-polygon',
        {
          inherit: 'polygon',
          width: 66,
          height: 36,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#5F95FF',
              fill: '#EFF4FF',
            },
            text: {
              fontSize: 12,
              color: '#262626',
            },
          },
          ports: this.ports
        },
        true,
      )

      Graph.registerNode(
        'custom-circle',
        {
          inherit: 'circle',
          width: 45,
          height: 45,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#5F95FF',
              fill: '#EFF4FF',
            },
            text: {
              fontSize: 12,
              color: '#262626',
            },
          },
          ports: this.ports
        },
        true,
      )

      Graph.registerNode(
        'custom-image',
        {
          inherit: 'rect',
          width: 52,
          height: 52,
          markup: [
            {
              tagName: 'rect',
              selector: 'body',
            },
            {
              tagName: 'image',
            },
            {
              tagName: 'text',
              selector: 'label',
            },
          ],
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#26C160',
              fill: '#26C160',
            },
            image: {
              width: 26,
              height: 26,
              refX: 13,
              refY: 16,
            },
            label: {
              refX: 3,
              refY: 2,
              textAnchor: 'left',
              textVerticalAnchor: 'top',
              fontSize: 12,
              fill: '#fff',
            },
          },
          ports: this.ports
        },
        true,
      )

      const stencil = new Addon.Stencil({
        search: (cell, keyword) => {
          if (keyword) {
            return cell.shape === 'rect' && cell.attr('label/text').includes(keyword)
          }
          return true
        },
        title: '流程图',
        target: graph,
        stencilGraphWidth: 200,
        stencilGraphHeight: 180,
        collapsable: true,
        groups: [
          {
            title: '基础流程图',
            name: 'group1',
          },
          {
            title: '系统设计图',
            name: 'group2',
            graphHeight: 250,
            layoutOptions: {
              rowHeight: 70,
            },
          },
        ],
        layoutOptions: {
          columns: 2,
          columnWidth: 80,
          rowHeight: 55,
        },
      })
      document.getElementById('stencil').appendChild(stencil.container)

      const r1 = graph.createNode({
        shape: 'custom-rect',
        attrs: {
          label: {
            text: "开始",
            fontSize: 12,
            fill: '#000000',
          },
          body: {
            fill: '#EFF4FF',
            rx: 20,
            ry: 26,
          },
        },
      })
      const r2 = graph.createNode({
        shape: 'custom-rect',
        attrs: {
          label: {
            text: "过程",
            fontSize: 12,
            fill: '#000000',
          }
        }
      })
      const r3 = graph.createNode({
        shape: 'custom-rect',
        attrs: {
          label: {
            text: "可选过程",
            fontSize: 12,
            fill: '#000000',
          },
          body: {
            rx: 6,
            ry: 6,
          },
        }
      })
      const r4 = graph.createNode({
        shape: 'custom-polygon',
        attrs: {
          label: {
            text: "决策",
            fontSize: 12,
            fill: '#000000',
          },
          body: {
            refPoints: '0,10 10,0 20,10 10,20',
          },
        }
      })
      const r5 = graph.createNode({
        shape: 'custom-polygon',
        attrs: {
          label: {
            text: "数据",
            fontSize: 12,
            fill: '#000000',
          },
          body: {
            refPoints: '10,0 40,0 30,20 0,20',
          },
        },
        label: '数据',
      })
      const r6 = graph.createNode({
        shape: 'custom-circle',
        attrs: {
          label: {
            text: "连接",
            fontSize: 12,
            fill: '#000000',
          },
        }
      })
      stencil.load([r1, r2, r3, r4, r5, r6], 'group1')

      const m1 = graph.createNode({
        shape: 'custom-image',
        label: 'Client',
        attrs: {
          label: {
            text: "Client",
            fontSize: 12,
            fill: '#ffffff',
          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg',
          },
        },
      })
      const m2 = graph.createNode({
        shape: 'custom-image',
        label: 'Http',
        attrs: {
          label: {
            text: "Http",
            fontSize: 12,
            fill: '#ffffff',
          },
          body: {
            stroke: '#2CB9FF',
            fill: '#2CB9FF',
          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg',
          },
        },
      })
      const m3 = graph.createNode({
        shape: 'custom-image',
        label: 'Api',
        attrs: {
          label: {
            text: "Api",
            fontSize: 12,
            fill: '#ffffff',
          },
          body: {
            stroke: '#5AB0BE',
            fill: '#5AB0BE',
          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg',
          },
        },
      })
      const m4 = graph.createNode({
        shape: 'custom-image',
        label: 'Sql',
        attrs: {
          label: {
            text: "Sql",
            fontSize: 12,
            fill: '#ffffff',
          },
          body: {
            stroke: '#E6475B',
            fill: '#E6475B',
          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg',
          },
        },
      })
      const m5 = graph.createNode({
        shape: 'custom-image',
        label: 'Clound',
        attrs: {
          label: {
            text: "Cloud",
            fontSize: 12,
            fill: '#ffffff',
          },
          body: {
            stroke: '#DA2625',
            fill: '#DA2625',

          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg',
          },
        },
      })
      const m6 = graph.createNode({
        shape: 'custom-image',
        label: 'Mq',
        attrs: {
          label: {
            text: "Mq",
            fontSize: 12,
            fill: '#ffffff',
          },
          body: {
            stroke: '#FFB15F',
            fill: '#FFB15F',
          },
          image: {
            'xlink:href':
              'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg',
          },
        },
      })

      stencil.load([m1, m2, m3, m4, m5, m6], 'group2');

      const container = document.getElementById('stencil')
      const ports = container.querySelectorAll(
        '.x6-port-body'
      )
      this.showPorts(ports, false);

    },
    showPorts(ports, show) {
      for (let i = 0, len = ports.length; i < len; i = i + 1) {
        ports[i].style.visibility = show ? 'visible' : 'hidden'
      }
    },
    // 拖拽生成正方形或者圆形
    startDrag(type, e) {
      startDragToGraph(this.graph, type, e)
    },
    // 删除节点
    deleteNode() {
      const cell = this.graph.getSelectedCells();
      console.log(cell)
      this.graph.removeCells(cell)
      this.type = 'grid';
      this.$Message.success("节点已删除")
    },
    delete(cellId) {
      if (this.graph.getSelectedCells().length > 0) {
        this.deleteNode();
        return;
      } else {
        const cell = this.graph.getCellById(cellId)
        console.log(cell);
        this.graph.removeCell(cell);
      }
      this.$Message.success("节点已删除")
      this.type = 'grid'
    },
    // 保存png
    saveToPNG() {
      this.$nextTick(() => {
        this.graph.toPNG((dataUri) => {
          // 下载
          DataUri.downloadDataUri(dataUri, '资产拓扑图.png')
        }, {
          backgroundColor: 'white',
          padding: {
            top: 50,
            right: 50,
            bottom: 50,
            left: 50
          },
          quality: 1,
          copyStyles: false
        })
      })

    },
    // 改变边形状
    changeEdgeType(e) {
      if (e === 'normal') {
        this.connectEdgeType = {
          connector: 'normal',
          router: {name: ''}
        }
        this.currentArrow = 1
      } else if (e === 'smooth') {
        this.connectEdgeType = {
          connector: 'smooth',
          router: {name: ''}
        }
        this.currentArrow = 2
      } else {
        this.connectEdgeType = {
          connector: 'normal',
          router: {name: 'manhattan'}
        }
        this.currentArrow = 3
      }
    },

  },
  mounted() {
    this.initX6();

    setTimeout(() => {
      this.showTips = true
    }, 1000)
    setTimeout(() => {
      this.showTips = false
    }, 5000)
  },
  beforeCreate () {
    document.querySelector('body').setAttribute('style', 'overflow: hidden;')
  },

  beforeDestroy () {
    this.graph.dispose();
  }
};
</script>
<style lang="less">
@import '../assets/iconfont.css';
// @import './index.less';
.main,
.container{
  position: fixed !important;
  right: 0;
  bottom: 0;
  background: #fff;
}

.x6-widget-stencil {
  position: absolute;
  width: 200px;
  top: 60px;
  right: 0;
  bottom: 0;
  left: 0;
}

.main {
  left: 0;
  top: 0;
}

.x6-widget-stencil {
  position: absolute;
  top: 60px;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 999;
}

.container{
  left: 200px;
  right: 300px;
  top: 60px;
  padding: 5px;
}

#headPanel {
  height: 60px;
  padding: 10px;
  line-height: 20px;
  background: #fff;
  position: relative;
  z-index: 11;
  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .1);
  transition: transform .3s ease-in-out;
}

.right_drawer {
  position: absolute;
  top: 60px;
  right: 0;
  bottom: 0;
  width: 25%;
  overflow: auto;
  background: #fff;
}
.minimapContainer{
  position: fixed;
  right: 20px;
  bottom: 20px;
  width: 200px;
  height: 200px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background-color: #fafbfc;
}
.btn-group {
  border-right: 1px solid #efefef;
  display: inline-block;
  padding-left: 10px;
  padding-right: 14px;
  position: relative;

  .btn-group_tips {
    text-align: center;
    top: 63px;
    left: 1px;
    position: absolute;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 120px;
    height: 60px;
    background: #515a6e;
    border-radius: 6px;
    animation: tips 4s;
    transition: all 1s;

    &:after {
      content: "";
      width: 0;
      height: 0;
      position: absolute;
      top: -5px;
      left: 46%;
      border-width: 0 5px 5px;
      border-style: solid;
      border-color: transparent transparent #515a6e;
    }
  }

  &:last-of-type {
    border-right: 0;
  }

  .btn {
    display: inline-block;
    margin: 2px;
    width: 30px;
    height: 30px;
    line-height: 30px;
    text-align: center;
    cursor: pointer;
    transition: all .4s;
    border-radius: 6px;
    border: 1px solid rgba(233, 233, 233, 0);

    i {
      font-size: 20px;
    }
  }

  .currentArrow {
    background: #2d8cf0;
    color: #fff;
  }
}


</style>
